`timescale 1ns/1ps

/*
    I2C 从机设备实现
    设备地址: 0x50
    寄存器地址 0x00 返回数据 0xA5
    支持 i2cget -y 11 0x50 0x00 命令
    作者: Claude
*/

module I2C_Slave_Device(
    input       sys_clk,        // 系统时钟
    input       rst_n,          // 系统复位，低电平有效
    
    input       i2c_scl,        // I2C时钟线输入
    inout       i2c_sda,        // I2C数据线
    
    output reg  [4:0] debug_state
);

// I2C从机状态定义
localparam IDLE           = 5'b0_0000;  // 0
localparam START_DET      = 5'b0_0001;  // 1
localparam ADDR_RX        = 5'b0_0010;  // 2
localparam WAIT_SDA_NPOS  = 5'b0_0011;  // 3
localparam ADDR_ACK       = 5'b0_0100;  // 4
localparam REG_RX         = 5'b0_0101;  // 5
localparam REG_ACK        = 5'b0_0110;  // 6
localparam WAIT_SDA_H     = 5'b0_0111;  // 7

localparam WAIT_STOP      = 5'b0_1000;  // 8
localparam RESTART_DET    = 5'b0_1001;  // 9
localparam ADDR_RX2       = 5'b0_1010;  // A
localparam ADDR_ACK2      = 5'b0_1011;  // B
localparam DATA_TX        = 5'b0_1100;  // C
localparam DATA_ACK       = 5'b0_1101;  // D
localparam WAIT_SDA_NPOS2 = 5'b0_1110;  // E
localparam WAIT_SDA_NPOS3 = 5'b0_1111;  // F; 介乎于ADDR_RX2=>ADDR_ACK2之间

localparam STOP_DET     = 5'b1_1111;  // 1F



// 设备地址
localparam DEVICE_ADDR = 7'b1010000;  // 0x50

// 寄存器
reg [7:0] memory [0:255];  // 256字节存储空间
reg [7:0] reg_addr;        // 当前寄存器地址

// I2C信号同步
reg i2c_scl_d1, i2c_scl_d2, i2c_scl_d3;
reg i2c_sda_d1, i2c_sda_d2;

// 边沿检测
wire scl_posedge = i2c_scl_d2 & ~i2c_scl_d3;
wire scl_negedge = ~i2c_scl_d2 & i2c_scl_d3;

wire sda_posedge = i2c_sda_d1 & ~i2c_sda_d2;
wire sda_negedge = ~i2c_sda_d1 & i2c_sda_d2;

// START和STOP条件检测
wire start_condition = i2c_scl_d1 & sda_negedge;
wire stop_condition = i2c_scl_d1 & sda_posedge;

// 状态机
reg [4:0] state, next_state, pre_next_state;
reg [2:0] bit_count;
reg [7:0] shift_reg;
reg [7:0] addr_reg;
reg sda_out;
reg sda_oe;  // SDA输出使能

// SDA三态控制
assign i2c_sda = sda_oe ? sda_out : 1'bz;

// 时钟同步
always @(posedge sys_clk or negedge rst_n) begin
    if (~rst_n) begin
        i2c_scl_d1 <= 1'b1;
        i2c_scl_d2 <= 1'b1;
        i2c_scl_d3 <= 1'b1;

        i2c_sda_d1 <= 1'b1;
        i2c_sda_d2 <= 1'b1;
    end else begin
        i2c_scl_d1 <= i2c_scl;
        i2c_scl_d2 <= i2c_scl_d1;
        i2c_scl_d3 <= i2c_scl_d2;

        i2c_sda_d1 <= i2c_sda;
        i2c_sda_d2 <= i2c_sda_d1;
    end
end

// 初始化内存
initial begin
    memory[0] = 8'h0;
    memory[1] = 8'hff;
    memory[2] = 8'hff;
    memory[3] = 8'hff;
    memory[4] = 8'hff;
    memory[5] = 8'hff;
    memory[6] = 8'hff;
    memory[7] = 8'h0;
    memory[8] = 8'h12;
    memory[9] = 8'he5;
    memory[10] = 8'h0;
    memory[11] = 8'h21;
    memory[12] = 8'h50;
    memory[13] = 8'h2d;
    memory[14] = 8'h31;
    memory[15] = 8'h1;
    memory[16] = 8'h1c;
    memory[17] = 8'h13;
    memory[18] = 8'h1;
    memory[19] = 8'h3;
    memory[20] = 8'h81;
    memory[21] = 8'h2f;
    memory[22] = 8'h1a;
    memory[23] = 8'h78;
    memory[24] = 8'h2e;
    memory[25] = 8'h35;
    memory[26] = 8'h85;
    memory[27] = 8'ha6;
    memory[28] = 8'h56;
    memory[29] = 8'h48;
    memory[30] = 8'h9a;
    memory[31] = 8'h24;
    memory[32] = 8'h12;
    memory[33] = 8'h50;
    memory[34] = 8'h54;
    memory[35] = 8'haf;
    memory[36] = 8'hef;
    memory[37] = 8'h0;
    memory[38] = 8'h1;
    memory[39] = 8'h1;
    memory[40] = 8'h1;
    memory[41] = 8'h1;
    memory[42] = 8'h1;
    memory[43] = 8'h1;
    memory[44] = 8'h1;
    memory[45] = 8'h1;
    memory[46] = 8'h1;
    memory[47] = 8'h1;
    memory[48] = 8'h1;
    memory[49] = 8'h1;
    memory[50] = 8'h1;
    memory[51] = 8'h1;
    memory[52] = 8'h1;
    memory[53] = 8'h1;
    memory[54] = 8'ha1;
    memory[55] = 8'h13;
    memory[56] = 8'h0;
    memory[57] = 8'h40;
    memory[58] = 8'h41;
    memory[59] = 8'h58;
    memory[60] = 8'h19;
    memory[61] = 8'h20;
    memory[62] = 8'h2c;
    memory[63] = 8'h58;
    memory[64] = 8'h36;
    memory[65] = 8'h0;
    memory[66] = 8'hdc;
    memory[67] = 8'h0c;
    memory[68] = 8'h11;
    memory[69] = 8'h0;
    memory[70] = 8'h0;
    memory[71] = 8'h1a;
    memory[72] = 8'h0;
    memory[73] = 8'h0;
    memory[74] = 8'h0;
    memory[75] = 8'hff;
    memory[76] = 8'h0;
    memory[77] = 8'h30;
    memory[78] = 8'h0a;
    memory[79] = 8'h0a;
    memory[80] = 8'h0a;
    memory[81] = 8'h0a;
    memory[82] = 8'h0a;
    memory[83] = 8'h0a;
    memory[84] = 8'h0a;
    memory[85] = 8'h0a;
    memory[86] = 8'h0a;
    memory[87] = 8'h0a;
    memory[88] = 8'h0a;
    memory[89] = 8'h0a;
    memory[90] = 8'h0;
    memory[91] = 8'h0;
    memory[92] = 8'h0;
    memory[93] = 8'hfd;
    memory[94] = 8'h0;
    memory[95] = 8'h38;
    memory[96] = 8'h4b;
    memory[97] = 8'h1e;
    memory[98] = 8'h53;
    memory[99] = 8'h15;
    memory[100] = 8'h0;
    memory[101] = 8'h0a;
    memory[102] = 8'h20;
    memory[103] = 8'h20;
    memory[104] = 8'h20;
    memory[105] = 8'h20;
    memory[106] = 8'h20;
    memory[107] = 8'h20;
    memory[108] = 8'h0;
    memory[109] = 8'h0;
    memory[110] = 8'h0;
    memory[111] = 8'hfc;
    memory[112] = 8'h0;
    memory[113] = 8'h48;
    memory[114] = 8'h44;
    memory[115] = 8'h4d;
    memory[116] = 8'h49;
    memory[117] = 8'h0a;
    memory[118] = 8'h0a;
    memory[119] = 8'h0a;
    memory[120] = 8'h0a;
    memory[121] = 8'h0a;
    memory[122] = 8'h0a;
    memory[123] = 8'h0a;
    memory[124] = 8'h0a;
    memory[125] = 8'h0a;
    memory[126] = 8'h1;
    memory[127] = 8'hf9;
    memory[128] = 8'h2;
    memory[129] = 8'h3;
    memory[130] = 8'h21;
    memory[131] = 8'h71;
    memory[132] = 8'h4e;
    memory[133] = 8'h6;
    memory[134] = 8'h7;
    memory[135] = 8'h2;
    memory[136] = 8'h3;
    memory[137] = 8'h15;
    memory[138] = 8'h96;
    memory[139] = 8'h11;
    memory[140] = 8'h12;
    memory[141] = 8'h13;
    memory[142] = 8'h4;
    memory[143] = 8'h14;
    memory[144] = 8'h5;
    memory[145] = 8'h1f;
    memory[146] = 8'h90;
    memory[147] = 8'h23;
    memory[148] = 8'h9;
    memory[149] = 8'h7;
    memory[150] = 8'h7;
    memory[151] = 8'h83;
    memory[152] = 8'h1;
    memory[153] = 8'h0;
    memory[154] = 8'h0;
    memory[155] = 8'h65;
    memory[156] = 8'h3;
    memory[157] = 8'h0c;
    memory[158] = 8'h0;
    memory[159] = 8'h10;
    memory[160] = 8'h0;
    memory[161] = 8'h8c;
    memory[162] = 8'h0a;
    memory[163] = 8'hd0;
    memory[164] = 8'h90;
    memory[165] = 8'h20;    // 8'h20;
    memory[166] = 8'h40;
    memory[167] = 8'h31;
    memory[168] = 8'h20;
    memory[169] = 8'h0c;
    memory[170] = 8'h40;
    memory[171] = 8'h55;
    memory[172] = 8'h0;
    memory[173] = 8'hb9;
    memory[174] = 8'h88;
    memory[175] = 8'h21;
    memory[176] = 8'h0;
    memory[177] = 8'h0;
    memory[178] = 8'h18;
    memory[179] = 8'h1;
    memory[180] = 8'h1d;
    memory[181] = 8'h80;
    memory[182] = 8'h18;
    memory[183] = 8'h71;
    memory[184] = 8'h1c;
    memory[185] = 8'h16;
    memory[186] = 8'h20;
    memory[187] = 8'h58;
    memory[188] = 8'h2c;
    memory[189] = 8'h25;
    memory[190] = 8'h0;
    memory[191] = 8'hb9;
    memory[192] = 8'h88;
    memory[193] = 8'h21;
    memory[194] = 8'h0;
    memory[195] = 8'h0;
    memory[196] = 8'h9e;
    memory[197] = 8'h1;
    memory[198] = 8'h1d;
    memory[199] = 8'h80;
    memory[200] = 8'hd0;
    memory[201] = 8'h72;
    memory[202] = 8'h1c;
    memory[203] = 8'h16;
    memory[204] = 8'h20;
    memory[205] = 8'h10;
    memory[206] = 8'h2c;
    memory[207] = 8'h25;
    memory[208] = 8'h80;
    memory[209] = 8'hb9;
    memory[210] = 8'h88;
    memory[211] = 8'h21;
    memory[212] = 8'h0;
    memory[213] = 8'h0;
    memory[214] = 8'h9e;
    memory[215] = 8'h1;
    memory[216] = 8'h1d;
    memory[217] = 8'h0;
    memory[218] = 8'hbc;
    memory[219] = 8'h52;
    memory[220] = 8'hd0;
    memory[221] = 8'h1e;
    memory[222] = 8'h20;
    memory[223] = 8'hb8;
    memory[224] = 8'h28;
    memory[225] = 8'h55;
    memory[226] = 8'h40;
    memory[227] = 8'hb9;
    memory[228] = 8'h88;
    memory[229] = 8'h21;
    memory[230] = 8'h0;
    memory[231] = 8'h0;
    memory[232] = 8'h1e;
    memory[233] = 8'h2;
    memory[234] = 8'h3a;
    memory[235] = 8'h80;
    memory[236] = 8'hd0;
    memory[237] = 8'h72;
    memory[238] = 8'h38;
    memory[239] = 8'h2d;
    memory[240] = 8'h40;
    memory[241] = 8'h10;
    memory[242] = 8'h2c;
    memory[243] = 8'h45;
    memory[244] = 8'h80;
    memory[245] = 8'hb9;
    memory[246] = 8'h88;
    memory[247] = 8'h21;
    memory[248] = 8'h0;
    memory[249] = 8'h0;
    memory[250] = 8'h1e;
    memory[251] = 8'h0;
    memory[252] = 8'h0;
    memory[253] = 8'h0;
    memory[254] = 8'h0;
    memory[255] = 8'hd0;
end

// 状态机时序逻辑
always @(posedge sys_clk or negedge rst_n) begin
    if (~rst_n) begin
        state <= IDLE;
        debug_state <= 3'b000;
//        pre_next_state <= IDLE;
    end else begin
        state <= next_state;
        debug_state <= state;
    end
end

// 状态机组合逻辑
always @(*) begin
    case (state)
        IDLE: begin
            if (start_condition)
                next_state = START_DET;
            else
                next_state = IDLE;
        end
        
        START_DET: begin
            next_state = ADDR_RX;
        end
        
        ADDR_RX: begin
            if (bit_count == 3'd7 && scl_posedge)
                next_state = WAIT_SDA_NPOS;
            else if (stop_condition)
                next_state = IDLE;
            else
                next_state = ADDR_RX;
        end
        
        WAIT_SDA_NPOS: begin
            if (scl_negedge)
                next_state = ADDR_ACK;
            else
                next_state = WAIT_SDA_NPOS;
        end

        ADDR_ACK: begin
            if (scl_negedge)
                if (addr_reg[7:1] == DEVICE_ADDR && addr_reg[0] == 1'b0)
                    next_state = REG_RX;  // 写操作
                else
                    next_state = IDLE;    // 地址不匹配
            else
                next_state = ADDR_ACK;
        end
        
        REG_RX: begin
            if (bit_count == 3'd7 && scl_posedge)
                // next_state = REG_ACK;
                next_state = WAIT_SDA_NPOS2;
                // next_state = IDLE;
            else if (stop_condition)
                next_state = IDLE;
            else
                next_state = REG_RX;
        end
        
        WAIT_SDA_NPOS2: begin
            if (scl_negedge)
                next_state = REG_ACK;
            else
                next_state = WAIT_SDA_NPOS2;
        end

        REG_ACK: begin
            if (scl_negedge)
                next_state = RESTART_DET;
            else
                next_state = REG_ACK;
        end
        
        RESTART_DET: begin
            if (start_condition)
                next_state = ADDR_RX2;
            else if (stop_condition)
                next_state = IDLE;
            else
                next_state = RESTART_DET;
        end
        
        ADDR_RX2: begin
            if (bit_count == 3'd7 && scl_posedge)
                next_state = WAIT_SDA_NPOS3;
            else if (stop_condition)
                next_state = IDLE;
            else
                next_state = ADDR_RX2;
        end

        WAIT_SDA_NPOS3: begin
            if (scl_negedge)
                next_state = ADDR_ACK2;
            else
                next_state = WAIT_SDA_NPOS3;
        end

        ADDR_ACK2: begin
            if (scl_negedge)
                if (addr_reg[7:1] == DEVICE_ADDR && addr_reg[0] == 1'b1)
                    next_state = DATA_TX;  // 读操作
                else
                    next_state = IDLE;     // 地址不匹配
            else
                next_state = ADDR_ACK2;
        end

        WAIT_STOP: begin
            if (stop_condition == 1'b0)
                next_state = RESTART_DET;  // 这里跳转得很快,基本一进来就跳了
            else
                next_state = WAIT_STOP;
        end
        
        DATA_TX: begin
            if (bit_count == 3'd8 && scl_negedge)
                next_state = DATA_ACK;
            else if (stop_condition)
                next_state = IDLE;
            else
                next_state = DATA_TX;
        end
        
        /// FIXME:人家SDA收满8bit就一直拉低SDA,不给你任何机会抓上升沿呀
        // WAIT_SDA_H: begin
        //     // if (i2c_pos == 1'b1)
        //     if (i2c_scl == 1'b0 && sda_posedge)
        //         next_state = DATA_ACK;
        //     else if (i2c_scl == 1'b1)
        //         next_state = DATA_ACK;
        //     else if (stop_condition)
        //         next_state = IDLE;
        //     else
        //         next_state = WAIT_SDA_H;
        // end
        
        DATA_ACK: begin
            if (scl_posedge)
                if (i2c_sda == 1'b1)    // NACK: 主机不再读取                    
                    pre_next_state = IDLE;
                else                    // ACK:主机请求读取下一个字节
                    pre_next_state = DATA_TX;
            /// FIXME:此处改动reg_addr会导致报错
            // reg_addr <= reg_addr + 8'd1;    // 地址自增
            if (scl_negedge)
                next_state = pre_next_state;
            else
                next_state = DATA_ACK;
        end
        
        STOP_DET: begin
            next_state = IDLE;
        end
        
        default: next_state = IDLE;
    endcase
end

// 位计数器
always @(posedge sys_clk or negedge rst_n) begin
    if (~rst_n) begin
        bit_count <= 3'd0;
    end else begin
        if (state == ADDR_RX || state == ADDR_RX2 || state == REG_RX || state == DATA_TX) begin
            if (scl_posedge) begin
                bit_count <= bit_count + 1;
            end
        end else begin
            bit_count <= 3'd0;
        end
    end
end

// 移位寄存器 - 接收数据
always @(posedge sys_clk or negedge rst_n) begin
    if (~rst_n) begin
        shift_reg <= 8'h00;
    end else begin
        if ((state == ADDR_RX || state == ADDR_RX2 || state == REG_RX) && scl_posedge) begin
            shift_reg <= {shift_reg[6:0], i2c_sda};
        end
    end
end

// 地址寄存器
always @(posedge sys_clk or negedge rst_n) begin
    if (~rst_n) begin
        addr_reg <= 8'h00;
    end else begin
        if ((state == ADDR_RX || state == ADDR_RX2) && scl_posedge) begin
            addr_reg <= {shift_reg[6:0], i2c_sda};
        end
    end
end

// 寄存器地址
always @(posedge sys_clk or negedge rst_n) begin
    if (~rst_n) begin
        reg_addr <= 8'h00;
    end else begin
        if (state == REG_RX && scl_posedge) begin
            reg_addr <= {shift_reg[6:0], i2c_sda};
        end else if (state == DATA_ACK && scl_negedge) begin // if (state == DATA_ACK && scl_negedge && i2c_sda == 1'b0)
            reg_addr <= reg_addr + 8'd1;
        end
    end
end

// SDA输出控制
always @(posedge sys_clk or negedge rst_n) begin
    if (~rst_n) begin
        sda_out <= 1'b1;
        sda_oe <= 1'b0;
    end else begin
        case (state)
            ADDR_ACK: begin
                if (addr_reg[7:1] == DEVICE_ADDR && addr_reg[0] == 1'b0) begin
                    sda_out <= 1'b0;  // ACK
                    sda_oe <= 1'b1;
                end else begin
                    sda_out <= 1'b1;  // NACK
                    sda_oe <= 1'b0;
                end
            end
            
            REG_ACK: begin
                sda_out <= 1'b0;  // ACK
                sda_oe <= 1'b1;
            end

            WAIT_STOP: begin
                sda_out <= 1'b1;
                sda_oe <= 1'b0;
            end
            
            ADDR_ACK2: begin
                if (addr_reg[7:1] == DEVICE_ADDR && addr_reg[0] == 1'b1) begin
                    sda_out <= 1'b0;  // ACK
                    sda_oe <= 1'b1;
                end else begin
                    sda_out <= 1'b1;  // NACK
                    sda_oe <= 1'b0;
                end
            end
            
            DATA_TX: begin
                // if (scl_negedge) begin
                if (((bit_count == 3'd0 && i2c_scl == 1'b0) || scl_negedge) && bit_count <= 3'd7) begin
                    sda_out <= memory[reg_addr][7-bit_count];
                    sda_oe <= 1'b1;
                end
            end
            WAIT_SDA_H: begin
                sda_out <= 1'b1;
                sda_oe <= 1'b0;  // 释放SDA，等待主机ACK/NACK
            end
            DATA_ACK: begin
                sda_oe <= 1'b0;  // 释放SDA，等待主机ACK/NACK
            end
            
            default: begin
                sda_out <= 1'b1;
                sda_oe <= 1'b0;
            end
        endcase
    end
end

endmodule